#include <poll.h>
#include <sys/epoll.h>
#include <unistd.h>
#include <cassert>
#include <errno.h>
#include <string.h>
#include <vector>

#include "EPollPoller.h"
#include "Channel.h"
#include "Logger.h"
#include "Poller.h"

// channel未添加到poller中
// channel中的index_ 就是 -1
const int KNew = -1;
// channel已经添加到poller中
const int KAdded = 1;
// channel从poller中删除
const int KDeleted = 2;

EPollPoller::EPollPoller(EventLoop *loop)
    :Poller(loop),
    epollfd_(::epoll_create1(EPOLL_CLOEXEC)),
    events_(KintEventListSize)
{
    if(epollfd_ < 0)
    {
        LOG_INFO("epoll_create error%d \n",errno); 
    }
}

EPollPoller::~EPollPoller()
{
    close(epollfd_);
}

Timestamp EPollPoller::poll(int timeousMs, ChannelList *activeChannels)
{
    LOG_INFO("func=%s => fd total count %d\n",__FUNCTION__,channels_.size());
    int numEvents = epoll_wait(epollfd_,&*events_.begin(),events_.size(),timeousMs);
    int savedError = errno;
    Timestamp now(Timestamp(Timestamp::now()));
    if(numEvents > 0)
    {
        LOG_INFO("%d Events happened\n",numEvents);
        fillActiveChannel(numEvents,activeChannels);
        // 如果达到了最大容量，需要扩容
        if(numEvents == events_.size())
        {
            events_.resize(events_.size()*2);
        }
    }
    else if(numEvents == 0)
    {
        LOG_INFO("nothing happened\n");
    }
    else
    {
        if(savedError != EINTR)
        {
            errno = savedError;
            LOG_ERROR("EPollPoller::poll()");
        }
    }

    return now;
}

void EPollPoller::updateChannel(Channel *channel)
{
    const int index = channel->index();
    LOG_INFO("func=%s fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->events(),channel->index());
    if(index == KNew || index == KDeleted)
    {
        int fd = channel->fd();
        if(index == KNew) 
        {
            assert(channels_.find(fd) == channels_.end());
            channels_[fd] = channel;
        } 
        else    // index == KDELETED 
        {
            assert(channels_.find(fd) != channels_.end());
            assert(channels_[fd] == channel);
        }

        channel->set_index(KAdded);
        update(EPOLL_CTL_ADD,channel);
    }
    else
    {
        int fd = channel->fd();
        (void)fd;
        assert(channels_.find(fd) != channels_.end());
        assert(channels_[fd] == channel);
        assert(index == KAdded);
        if(channel->isNoneEvent())
        {
            update(EPOLL_CTL_DEL,channel);
            channel->set_index(KDeleted);
        } 
        else 
        {
            update(EPOLL_CTL_MOD,channel);
        }
    }
}

void EPollPoller::removeChannel(Channel *channel)
{
    int fd = channel->fd();
    LOG_INFO("func=%s fd=%d events=%d index=%d \n",__FUNCTION__,channel->fd(),channel->events(),channel->index());
    channels_.erase(fd);

    int index = channel->index();
    if(index == KAdded)
    {
        // 从epoll中删除
        update(EPOLL_CTL_DEL,channel);
    }

    channel->set_index(KNew);
}

void EPollPoller::fillActiveChannel(int numEvents, ChannelList *activeChannels) const
{
    for(int i =0; i<numEvents; i++)
    {
        Channel* channel = static_cast<Channel*>(events_[i].data.ptr);
        channel->set_revents(events_[i].events);
        activeChannels->push_back(channel);
    } 
}
void EPollPoller::update(int operation, Channel *channel)
{
    struct epoll_event event;
    memset(&event,0,sizeof(event));
    int fd = channel->fd();
    event.events = channel->events();
    event.data.fd = fd; 
    event.data.ptr = channel;

    if(epoll_ctl(epollfd_,operation,fd,&event) < 0)
    {
        if(operation == EPOLL_CTL_DEL)
        {
            LOG_ERROR("epoll_ctl del error:%d\n",errno);
        }
        else
        {
            LOG_FATAL("epoll_ctl add/mod error:%d\n",errno);
        }
    }
}
